// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CommandRouter.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Windows.Input.Commands
{
    using System.Linq;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;

    public class CommandRouter : ICommandRouter
    {
        private readonly CommandBindingCollection _commandBindings;

        public CommandRouter()
        {
            _commandBindings = new CommandBindingCollection();
        }

        public void Execute(ICommand command, object context, object parameter)
        {
            var binding = FindBinding(context, command);
            if (binding != null)
            {
                binding.Execute(parameter);
            }
        }

        public bool CanExecute(ICommand command, object context, object parameter)
        {
            var binding = FindBinding(context, command);
            return binding != null &&
                binding.CanExecute(parameter);
        }

        private CommandBinding FindBinding(object context, ICommand command)
        {
            while (context != null)
            {
                var contextAsBindingSource = context as ICommandBindingSource;
                if (contextAsBindingSource != null)
                {
                    var result = contextAsBindingSource.FindBinding(command);
                    if (result != null)
                    {
                        return result;
                    }
                }

                context = GetContextParent(context);
            }

            return _commandBindings.FirstOrDefault((cb) => cb.Command == command);
        }

        protected virtual object GetContextParent(object context)
        {
            var dependencyObject = context as DependencyObject;

            // walk up visual tree
            return dependencyObject != null ? VisualTreeHelper.GetParent(dependencyObject) : null;
        }

        public CommandBindingCollection CommandBindings
        {
            get { return _commandBindings; }
        }
    }
}